/**	servlet is the entrance of program
 * system core servlet,it contains admin login/logout/query admin account
 * servlet layer implements verification of parameter
 * response encapsulated in business module due to content maybe text or image
 * by fuzhou huilin corp. ltd @author lms 2016.07.18
 */
package com.fzrskj.cloud.free.thridparty.pay.alipay;

import com.fzrskj.cloud.free.core.enums.DicParamEnum;
import com.fzrskj.cloud.free.core.tool.*;
import com.fzrskj.cloud.free.core.utils.CloudContextUtils;
import com.fzrskj.cloud.free.core.utils.DoubleUtil;
import com.fzrskj.cloud.free.dic.utils.DicParamUtils;
import com.fzrskj.cloud.free.user.bean.UserCharge;
import com.fzrskj.cloud.free.user.utils.FuncHandleUtils;
import com.fzrskj.cloud.free.user.utils.UserChargeUtils;
import com.fzrskj.cloud.free.user.utils.UserLogUtils;
import com.winiis.component.utils.client.RestClientUtils;
import ms.core.db.ConnectionContext;
import ms.core.tool.HttpTool;
import ms.core.tool.StrTool;
import net.sf.json.JSONObject;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.util.*;

public class AlipayReceiveServlet extends HttpServlet {

	//servlet serial id
	private static final long serialVersionUID = 2000L;

	//constructor function, you can do some initialize here
	public AlipayReceiveServlet() {
		super();
	}

	//Destruction of the servlet. <br>
	@Override
	public void destroy() {
		super.destroy(); // Just puts "destroy" string in log
		// Put your code here
	}

	/**the entrance of system servlet with get method
	 * This method is called when a form has its tag value method equals to get.
	 * @param request the request send by the client to the server
	 * @param response the response send by the server to the client
	 * @throws ServletException if an error occurred
	 * @throws IOException if an error occurred
	 */
	@Override
	public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		doPost(request,response);
	}

	boolean canContinueDealOrder = true;
	Integer agentId = 0;

	/**
	 * The doPost method of the servlet. <br>
	 * This method is called when a form has its tag value method equals to post.
	 * 
	 * @param request the request send by the client to the server
	 * @param response the response send by the server to the client
	 * @throws ServletException if an error occurred
	 * @throws IOException if an error occurred
	 */
	@SuppressWarnings("unchecked")
	@Override
	public void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

		try {

			request.setCharacterEncoding("UTF-8");

			Map<String, String[]> params = request.getParameterMap();
			//获得参数
			String queryString = "";
			String torderid = "";
			for (String key : params.keySet()) {
				String[] values = params.get(key);
				for (int i = 0; i < values.length; i++) {
					String value = new String(values[i].getBytes("ISO-8859-1"), "UTF-8");
					key = new String(key.getBytes("ISO-8859-1"), "UTF-8");

					//获取订单号
					if (key.equals("extra_common_param")) {
						torderid = value;
					}

					queryString += key + "=" + value + "&";
				}
			}
			String sid = CCookieTool.getSessionId(request);
			CCookieTool.refreshSessionId(request, response, sid);

			// 去掉最后一个&
			if (queryString.length() > 10) {
				queryString = queryString.substring(0, queryString.length() - 1);
			}

			//记录日志
			UserLogUtils.addLog(this, CCookieTool.getUid(request), "收到支付宝入请帐求:【" + queryString + "】");

			//处理通知
			String content = this.alipayReceive(queryString);
			String code = CJsonTool.getStrValue(content, "code", null);

			//充值成功，处理订单
			if (torderid.length() > 1 && code.equals("success") && this.canContinueDealOrder) {
				FuncHandleUtils hand = new FuncHandleUtils();
				String[] orders = torderid.split(",");
				for (int i = 0; i < orders.length; i++) {
					hand.HandleOnLine(orders[i]);
				}
				hand = null;
			}

			//通知订单发起代理，触发充值关联订单处理操作
			if (!StrTool.isBlankStr(torderid) && !this.canContinueDealOrder) {
				String webUrl = DicParamUtils.getParamValueByAgentIdAndParamName("weburl", this.agentId);
				webUrl += (webUrl.endsWith("/") ? "" : "/") + "pay_success?type=alipay&orderId=" + torderid;
				RestClientUtils clientUtils = new RestClientUtils();
				String noticeResponse = clientUtils.get(webUrl);
				UserLogUtils.addLog(this, CloudContextUtils.getAdminId(), "通知代理充值结果，请求地址：[" +
						webUrl + "]，映应结果：[" + com.alibaba.fastjson.JSONObject.toJSONString(noticeResponse) + "]");
			}

			//输出到页面
			response.setContentType("text/html ");
			response.setCharacterEncoding("UTF-8");
			PrintWriter out = response.getWriter();
			out.println("success");
		} finally {
			ConnectionContext.closeAllConnection();
		}
	}

	/**Initialization of the servlet. <br>
	 * @throws ServletException if an error occurs
	 */
	@Override
	public void init() throws ServletException {
		//TODO Put your code here
	}
	
	/**
	 * 支付宝通知
	 * @return
	 * @throws UnsupportedEncodingException 
	 */
	public  String alipayReceive(String url){
		JSONObject obj_result = new JSONObject();
		if ( CStrTool.isBlankStr(url) ) {
			obj_result.put("code", "fail");
			obj_result.put("message", "参数错误");
			return obj_result.toString();
		}
		String alipayway = DicParamUtils.getParamValue("alipayac_way");//1 使用自己的签约帐号  2 使用慧林的支付宝帐号
		String alipayUrl = DicParamUtils.getParamValue("alipaycomweb");//网址
		String partnerId="";//合作伙伴ID
		String alipaykey = DicParamUtils.getParamValue("alipaykey");
		String md5Str = "" ;	//MD5加密串
		String userName ="";
		int userId = 0; 
		String md5Strbefore = "";//MD5加密字符串
		String[] keyv;
		String message="";
		String seller_email="";	//收款帐号
		String orderId ="" ;	//订单号
		String sign = "";		//校验码
		String tradeStatus="";	//交易状态
		String notifyid = "";
		String totalfee = "" ;	//交易金额
		
		String alipayNotifyURL = "https://mapi.alipay.com/gateway.do?";//通过通知ID确认是否是支付宝消息
		String getpanersURL = "http://www.winiis.com/tools/alipay/alipay_getpaners.asp?";//使用慧林支付宝网关时获取验证参数
		String HlGateway = "http://www.winiis.com/tools/alipay/alipay_gateway.asp?";//支付宝网关加密
		
		HttpTool http = new HttpTool();
		UserChargeUtils uCharge =new UserChargeUtils();
		try{
			
			//获取UEL参数
			String[]  param=url.split("&");
			List<String> parameters = new ArrayList<String>();
			for(int i = 0;i<param.length;i++){
				parameters.add(param[i]);
			}
			
			//排序
			Collections.sort(parameters);
			
			//获取判断参数
			for(int i = 0;i<parameters.size();i++){
				keyv = parameters.get(i).split("=");
				//获取支付宝订单号
				if(keyv[0].equals("out_trade_no")) {
					orderId = keyv[1];
				}
				
				//获取支付宝加密字符串
				if(keyv[0].equals("sign")) {
					sign = keyv[1];
				}
				
				//获取交易状态
				if(keyv[0].equals("trade_status")) {
					tradeStatus = keyv[1];
				}
				
				//获取通知ID
				if(keyv[0].equals("notify_id")) {
					notifyid = keyv[1];
				}
				
				//获取交易金额
				if(keyv[0].equals("total_fee")) {
					totalfee = keyv[1];
				}
				
				//获取收款方支付宝帐号
				if(keyv[0].equals("seller_email")) {
					seller_email = keyv[1];
				}
				
				if(!("".equals(keyv[0])||"sign".equals(keyv[0])||"sign_type".equals(keyv[0]))){
					if("".equals(md5Strbefore)) {
						md5Strbefore = keyv[0] + "=" + keyv[1];
					} else {
						md5Strbefore = md5Strbefore + "&" + keyv[0] + "=" + keyv[1];
					}
				}
			}
			
			//获取合作伙伴ID
			if(alipayway.equals("2")){
				String url2 = alipayUrl + "/alipay_return";
				String partnerURL = getpanersURL+"url="+url2+"&email="+seller_email+"&pamer=partner" ;
				partnerId = http.httpGet(partnerURL);
			}else{			
				partnerId = DicParamUtils.getParamValue("alipaypartnerid");
			}		
			
			//判断是否存在该条充值记录
			UserCharge usercharge = uCharge.getUserCharge(orderId);
			if(usercharge==null){
				message = "未知单号["+orderId+"]，系统自动入帐失败";	
				UserLogUtils.addLog(this, 0, message);
				obj_result.put("code", "fail");
				obj_result.put("message", message);
				return obj_result.toString();		
			}
			
			//从订单里获取用户信息
			userName = usercharge.getUserName();
			userId = usercharge.getUserId();
			
			//校验是否为支付宝请求
			alipayNotifyURL	= alipayNotifyURL + "service=notify_verify&agent="+ partnerId +"&partner=" + partnerId + "&notify_id=" + notifyid;
			String ResponseTxt=http.httpGet(alipayNotifyURL);
			if(!"true".equals(ResponseTxt)){
				message = "系统自动入帐失败：不是支付宝通知";
				UserLogUtils.addLog(this, userId, message);
				obj_result.put("code", "fail");
				obj_result.put("message", message);
				return obj_result.toString();
			}
			
			//对返回的参数进行MD5加密
			if(alipayway.equals("2")){
				md5Strbefore= CEncryptTool.base64Encode(md5Strbefore);
				md5Strbefore=CEncryptTool.httpEncode(md5Strbefore, "UTF8");
				String md5URL = HlGateway + "md5str=" + md5Strbefore + "&otime=" + CDateTimeTool.formatDateTime(new Date(),"yyyy-M-d H:m:s");	;
				md5Str = http.httpGet(md5URL.replaceAll(" ", "+")); 
			}else{
				md5Str = CEncryptTool.md5Encode(md5Strbefore + alipaykey);
			}
			
			//验证签名
			if(!md5Str.equals(sign)){
				message = "系统自动入帐失败:验证签名失败";
				UserLogUtils.addLog(this, userId, message);
				obj_result.put("code", "fail");
				obj_result.put("message", message);
				return obj_result.toString();
			}
			
			//验证支付状态
			if(!(tradeStatus.equals("TRADE_SUCCESS") || tradeStatus.equals("TRADE_FINISHED"))){
				message = "系统自动入帐失败：支付失败";
				UserLogUtils.addLog(this, userId, message);
				obj_result.put("code", "fail");
				obj_result.put("message", message);
				return obj_result.toString();
			}
			
			//验证订单是否已入账
			if(usercharge.getStatus().equals("Y")){
				message = "单号["+orderId+"]已入帐，请勿重复提交";
				UserLogUtils.addLog(this, userId,message);
				obj_result.put("code", "success");
				obj_result.put("message", message);
				return obj_result.toString();
			}			
			
			//入帐金额
			double inAmount=Double.valueOf(totalfee);
			if(inAmount!=usercharge.getAmount()){
				message = "系统自动入帐失败：支付金额["+usercharge.getAmount()+"]与入帐金额["+inAmount+"]不符";
				UserLogUtils.addLog(this, userId, message);
				obj_result.put("code", "fail");
				obj_result.put("message", message);
				return obj_result.toString();
			}
			
			//系统入账
			FuncHandleUtils funcHandle = new FuncHandleUtils();
			String remark="支付宝在线支付，支付订单号【"+orderId+"】";
			//费率计算
			String rateStr = DicParamUtils.getParamValue(DicParamEnum.ALIPAY_RATE.getVal());
			if (StrTool.isBlankStr(rateStr)) {
				rateStr = "0";
			}
			Double rateDouble = Double.valueOf(rateStr);
			Double rate = DoubleUtil.sub(1.0, DoubleUtil.divide(rateDouble, 100.0));
			Double realAmount = DoubleUtil.mul(rate, inAmount, 2);
			Double rateAmount = DoubleUtil.sub(inAmount, realAmount, 2);
			remark += "；费率：" + String.valueOf(rateAmount);

			String result=funcHandle.FinanceAccount(userName,100,remark,orderId,"alipay","",realAmount, userName, usercharge.getAgentId());

			//生成财务记录并更新充值记录状态
			JSONObject obj = new JSONObject();
			obj= JSONObject.fromObject(result);
			if("0".equals(obj.getString("code").trim())){

				//如果是下级代理的会员入款，需要为中间所有的代理账户入款
				if (!usercharge.getAgentId().equals(usercharge.getFromAgentUserId())) {
					this.canContinueDealOrder = false;
					this.agentId = usercharge.getAgentId();
					funcHandle.refundsForAgent(usercharge.getAgentId(), usercharge.getFromAgentUserId(), orderId, "alipay", "", realAmount, userName, remark);
				}

				usercharge.setStatus("Y");
				uCharge.uptUsercharge(usercharge);
				message="支付宝支付成功，系统自动入账成功";
				UserLogUtils.addLog(this, userId, message, usercharge.getAgentId());
				
				//更新会员等级
				FuncHandleUtils hand=new  FuncHandleUtils();
				hand.uptVipgrade(orderId);
				hand = null;
				
				obj_result.put("code", "success");
				obj_result.put("message", message);
			}else{
				message = "在线支付宝支付成功，系统自动入账失败！";
				UserLogUtils.addLog(this, userId, message, usercharge.getAgentId());
				obj_result.put("addLog", "fail");
				obj_result.put("message", message);
			}	
		}catch (Exception e) {
			e.printStackTrace();
			message = "内部错误：" + e.getMessage();
			UserLogUtils.addLog(this, userId, message);
			obj_result.put("code", "fail");
			obj_result.put("message", message);
		}
		return obj_result.toString();
	}
}
